Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-076.rds.xz")
summary(model)
SOM of size 10x10 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 1065343 objects.
Mean distance to the closest unit in the map: 0.167.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_dia_2k.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt          tmax       
 Length:1065343     Length:1065343     Min.   :  1.0   Min.   :-196.0  
 Class :character   Class :character   1st Qu.: 91.0   1st Qu.: 144.0  
 Mode  :character   Mode  :character   Median :183.0   Median : 201.0  
                                       Mean   :182.8   Mean   : 201.5  
                                       3rd Qu.:274.0   3rd Qu.: 263.0  
                                       Max.   :366.0   Max.   : 469.0  
      tmin             precip            nevada    prof_nieve       
 Min.   :-252.00   Min.   :   0.00   Min.   :0   Min.   :   0.0000  
 1st Qu.:  47.00   1st Qu.:   0.00   1st Qu.:0   1st Qu.:   0.0000  
 Median : 100.00   Median :   0.00   Median :0   Median :   0.0000  
 Mean   :  97.54   Mean   :  17.05   Mean   :0   Mean   :   0.6185  
 3rd Qu.: 153.00   3rd Qu.:   2.00   3rd Qu.:0   3rd Qu.:   0.0000  
 Max.   : 332.00   Max.   :3361.00   Max.   :0   Max.   :1240.0000  
    longitud        latitud           altitud    
 Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:39.47   1st Qu.: -4.850   1st Qu.:  47  
 Median :41.29   Median : -1.411   Median : 287  
 Mean   :40.10   Mean   : -2.391   Mean   : 486  
 3rd Qu.:42.22   3rd Qu.:  1.296   3rd Qu.: 691  
 Max.   :43.57   Max.   :  4.216   Max.   :2535  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

    1     2     3     4     5     6     7     8     9    10    11    12    13 
 8148  2306  2075  1778    51   196  1246  2253  6331  2298 13550 12616  6862 
   14    15    16    17    18    19    20    21    22    23    24    25    26 
 3459   910   600   829  7198  4954  9556 14734  6954  7352  2686  1529  1506 
   27    28    29    30    31    32    33    34    35    36    37    38    39 
 4283 10641 16091  9846 15233 10246 18604 11849  5019  2838  7484 13598  5304 
   40    41    42    43    44    45    46    47    48    49    50    51    52 
15764  8997 15031  7561  7645 14351  6254  9594 17384 12132 14217 13926  5687 
   53    54    55    56    57    58    59    60    61    62    63    64    65 
16462  9783 10368 15117 11389 12104  9392 17585  8178 16782 11428 10021 12011 
   66    67    68    69    70    71    72    73    74    75    76    77    78 
11419 18987 14994 11768 17071 14855 16888 11584 18293 15243 12973 13855 12805 
   79    80    81    82    83    84    85    86    87    88    89    90    91 
10334 11772 17336 16130 17420 15449 18599 18266 12489  3955  4888 15219 17505 
   92    93    94    95    96    97    98    99   100 
18121 12756 14320 15446 19637 12959 17163 12320 10348 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 10*10;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
       fecha_cnt       tmax       tmin      precip
[1,] -0.92431735 -0.3191600 -0.3382791  0.01985306
[2,] -0.05654333  0.8214148  0.8377522 -0.26431874

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
   precip fecha_cnt      tmin      tmax 
0.9825116 0.9789365 0.9783541 0.9762415 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 91.0   1st Qu.: 145.0   1st Qu.:  47.00   1st Qu.:  0.00  
 Median :183.0   Median : 201.0   Median : 100.00   Median :  0.00  
 Mean   :182.7   Mean   : 201.7   Mean   :  97.59   Mean   : 15.33  
 3rd Qu.:274.0   3rd Qu.: 263.0   3rd Qu.: 153.00   3rd Qu.:  1.00  
 Max.   :366.0   Max.   : 469.0   Max.   : 332.00   Max.   :567.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.47   1st Qu.: -4.850  
 Median :0   Median :   0.0000   Median :41.29   Median : -1.411  
 Mean   :0   Mean   :   0.6114   Mean   :40.10   Mean   : -2.394  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.22   3rd Qu.:  1.296  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 287.0  
 Mean   : 485.5  
 3rd Qu.: 690.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   : 21.0   Min.   : 17.0   Min.   :-41.00   Min.   :1528   Min.   :0  
 1st Qu.: 86.0   1st Qu.: 81.5   1st Qu.: 47.00   1st Qu.:1576   1st Qu.:0  
 Median :286.0   Median :126.0   Median : 90.00   Median :1741   Median :0  
 Mean   :219.8   Mean   :136.5   Mean   : 91.35   Mean   :1820   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194.5   3rd Qu.:146.50   3rd Qu.:2036   3rd Qu.:0  
 Max.   :333.0   Max.   :252.0   Max.   :192.00   Max.   :3361   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0    1st Qu.:39.48   1st Qu.:  0.3181   1st Qu.:  69.0  
 Median :0    Median :40.80   Median :  0.4731   Median : 333.0  
 Mean   :0    Mean   :39.48   Mean   : -1.2462   Mean   : 627.3  
 3rd Qu.:0    3rd Qu.:41.72   3rd Qu.:  1.6841   3rd Qu.:1055.0  
 Max.   :0    Max.   :43.36   Max.   :  2.4378   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip         nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   : 437   Min.   :0  
 1st Qu.: 82.0   1st Qu.: 82.0   1st Qu.:  36.50   1st Qu.: 568   1st Qu.:0  
 Median :243.0   Median :134.0   Median :  88.00   Median : 647   Median :0  
 Mean   :198.6   Mean   :131.1   Mean   :  77.81   Mean   : 704   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:179.0   3rd Qu.: 127.00   3rd Qu.: 787   3rd Qu.:0  
 Max.   :366.0   Max.   :344.0   Max.   : 240.00   Max.   :1500   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.82   1st Qu.: -2.0392   1st Qu.:  59.0  
 Median :  0.000   Median :41.83   Median :  0.8856   Median : 287.0  
 Mean   :  3.601   Mean   :41.00   Mean   : -0.8206   Mean   : 700.4  
 3rd Qu.:  0.000   3rd Qu.:42.39   3rd Qu.:  1.9756   3rd Qu.:1055.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip       
 Min.   :  1.0   Min.   :-196.0   Min.   :-252.00   Min.   :  0.000  
 1st Qu.: 92.0   1st Qu.: 146.0   1st Qu.:  47.00   1st Qu.:  0.000  
 Median :184.0   Median : 203.0   Median : 100.00   Median :  0.000  
 Mean   :183.4   Mean   : 203.4   Mean   :  98.34   Mean   :  9.358  
 3rd Qu.:274.0   3rd Qu.: 264.0   3rd Qu.: 154.00   3rd Qu.:  1.000  
 Max.   :366.0   Max.   : 469.0   Max.   : 332.00   Max.   :315.000  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.47   1st Qu.: -4.850  
 Median :0   Median :   0.0000   Median :41.22   Median : -1.411  
 Mean   :0   Mean   :   0.5209   Mean   :40.07   Mean   : -2.407  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.18   3rd Qu.:  1.296  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 286.0  
 Mean   : 480.6  
 3rd Qu.: 690.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 70.0   Min.   :0  
 1st Qu.: 64.0   1st Qu.:  91.0   1st Qu.:  31.00   1st Qu.:188.0   1st Qu.:0  
 Median :126.0   Median : 136.0   Median :  76.00   Median :242.0   Median :0  
 Mean   :157.2   Mean   : 131.1   Mean   :  67.38   Mean   :257.8   Mean   :0  
 3rd Qu.:273.0   3rd Qu.: 178.0   3rd Qu.: 114.00   3rd Qu.:313.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :567.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:   0.000   1st Qu.:40.87   1st Qu.: -4.8458   1st Qu.:  81  
 Median :   0.000   Median :42.08   Median :  0.3056   Median : 370  
 Mean   :   4.288   Mean   :41.28   Mean   : -1.8850   Mean   : 683  
 3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.5242   3rd Qu.: 916  
 Max.   :1199.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   : 21.0   Min.   : 17.0   Min.   :-41.00   Min.   :1528   Min.   :0  
 1st Qu.: 86.0   1st Qu.: 81.5   1st Qu.: 47.00   1st Qu.:1576   1st Qu.:0  
 Median :286.0   Median :126.0   Median : 90.00   Median :1741   Median :0  
 Mean   :219.8   Mean   :136.5   Mean   : 91.35   Mean   :1820   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194.5   3rd Qu.:146.50   3rd Qu.:2036   3rd Qu.:0  
 Max.   :333.0   Max.   :252.0   Max.   :192.00   Max.   :3361   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0    1st Qu.:39.48   1st Qu.:  0.3181   1st Qu.:  69.0  
 Median :0    Median :40.80   Median :  0.4731   Median : 333.0  
 Mean   :0    Mean   :39.48   Mean   : -1.2462   Mean   : 627.3  
 3rd Qu.:0    3rd Qu.:41.72   3rd Qu.:  1.6841   3rd Qu.:1055.0  
 Max.   :0    Max.   :43.36   Max.   :  2.4378   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin             precip         nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   : 437   Min.   :0  
 1st Qu.: 82.0   1st Qu.: 82.0   1st Qu.:  36.50   1st Qu.: 568   1st Qu.:0  
 Median :243.0   Median :134.0   Median :  88.00   Median : 647   Median :0  
 Mean   :198.6   Mean   :131.1   Mean   :  77.81   Mean   : 704   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:179.0   3rd Qu.: 127.00   3rd Qu.: 787   3rd Qu.:0  
 Max.   :366.0   Max.   :344.0   Max.   : 240.00   Max.   :1500   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.82   1st Qu.: -2.0392   1st Qu.:  59.0  
 Median :  0.000   Median :41.83   Median :  0.8856   Median : 287.0  
 Mean   :  3.601   Mean   :41.00   Mean   : -0.8206   Mean   : 700.4  
 3rd Qu.:  0.000   3rd Qu.:42.39   3rd Qu.:  1.9756   3rd Qu.:1055.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin            precip       
 Min.   :  4.0   Min.   :-158.0   Min.   :-240.0   Min.   :  0.000  
 1st Qu.:215.0   1st Qu.: 171.0   1st Qu.:  75.0   1st Qu.:  0.000  
 Median :265.0   Median : 246.0   Median : 135.0   Median :  0.000  
 Mean   :263.8   Mean   : 232.1   Mean   : 123.4   Mean   :  9.772  
 3rd Qu.:316.0   3rd Qu.: 297.0   3rd Qu.: 178.0   3rd Qu.:  0.000  
 Max.   :366.0   Max.   : 469.0   Max.   : 332.0   Max.   :315.000  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.01   1st Qu.: -4.846  
 Median :0   Median :   0.0000   Median :41.17   Median : -1.411  
 Mean   :0   Mean   :   0.1697   Mean   :40.04   Mean   : -2.341  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.11   3rd Qu.:  1.296  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 261.0  
 Mean   : 451.2  
 3rd Qu.: 674.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 70.0   Min.   :0  
 1st Qu.: 64.0   1st Qu.:  91.0   1st Qu.:  31.00   1st Qu.:188.0   1st Qu.:0  
 Median :126.0   Median : 136.0   Median :  76.00   Median :242.0   Median :0  
 Mean   :157.2   Mean   : 131.1   Mean   :  67.38   Mean   :257.8   Mean   :0  
 3rd Qu.:273.0   3rd Qu.: 178.0   3rd Qu.: 114.00   3rd Qu.:313.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :567.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:   0.000   1st Qu.:40.87   1st Qu.: -4.8458   1st Qu.:  81  
 Median :   0.000   Median :42.08   Median :  0.3056   Median : 370  
 Mean   :   4.288   Mean   :41.28   Mean   : -1.8850   Mean   : 683  
 3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.5242   3rd Qu.: 916  
 Max.   :1199.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   : 21.0   Min.   : 17.0   Min.   :-41.00   Min.   :1528   Min.   :0  
 1st Qu.: 86.0   1st Qu.: 81.5   1st Qu.: 47.00   1st Qu.:1576   1st Qu.:0  
 Median :286.0   Median :126.0   Median : 90.00   Median :1741   Median :0  
 Mean   :219.8   Mean   :136.5   Mean   : 91.35   Mean   :1820   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194.5   3rd Qu.:146.50   3rd Qu.:2036   3rd Qu.:0  
 Max.   :333.0   Max.   :252.0   Max.   :192.00   Max.   :3361   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0    1st Qu.:39.48   1st Qu.:  0.3181   1st Qu.:  69.0  
 Median :0    Median :40.80   Median :  0.4731   Median : 333.0  
 Mean   :0    Mean   :39.48   Mean   : -1.2462   Mean   : 627.3  
 3rd Qu.:0    3rd Qu.:41.72   3rd Qu.:  1.6841   3rd Qu.:1055.0  
 Max.   :0    Max.   :43.36   Max.   :  2.4378   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin             precip         nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   : 437   Min.   :0  
 1st Qu.: 82.0   1st Qu.: 82.0   1st Qu.:  36.50   1st Qu.: 568   1st Qu.:0  
 Median :243.0   Median :134.0   Median :  88.00   Median : 647   Median :0  
 Mean   :198.6   Mean   :131.1   Mean   :  77.81   Mean   : 704   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:179.0   3rd Qu.: 127.00   3rd Qu.: 787   3rd Qu.:0  
 Max.   :366.0   Max.   :344.0   Max.   : 240.00   Max.   :1500   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.82   1st Qu.: -2.0392   1st Qu.:  59.0  
 Median :  0.000   Median :41.83   Median :  0.8856   Median : 287.0  
 Mean   :  3.601   Mean   :41.00   Mean   : -0.8206   Mean   : 700.4  
 3rd Qu.:  0.000   3rd Qu.:42.39   3rd Qu.:  1.9756   3rd Qu.:1055.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin             precip       
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.000  
 1st Qu.: 42.00   1st Qu.: 130.0   1st Qu.:  28.00   1st Qu.:  0.000  
 Median : 84.00   Median : 173.0   Median :  70.00   Median :  0.000  
 Mean   : 86.01   Mean   : 168.7   Mean   :  68.01   Mean   :  8.858  
 3rd Qu.:126.00   3rd Qu.: 215.0   3rd Qu.: 109.00   3rd Qu.:  2.000  
 Max.   :254.00   Max.   : 349.0   Max.   : 239.00   Max.   :172.000  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.48   1st Qu.: -5.346  
 Median :0   Median :   0.0000   Median :41.32   Median : -1.636  
 Mean   :0   Mean   :   0.9457   Mean   :40.11   Mean   : -2.487  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.26   3rd Qu.:  1.272  
 Max.   :0   Max.   :1209.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 333.0  
 Mean   : 516.2  
 3rd Qu.: 775.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  4.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.00  
 1st Qu.:273.0   1st Qu.: 134.0   1st Qu.:  40.00   1st Qu.:  0.00  
 Median :307.0   Median : 186.0   Median :  89.00   Median :  0.00  
 Mean   :298.7   Mean   : 177.9   Mean   :  84.64   Mean   : 15.99  
 3rd Qu.:337.0   3rd Qu.: 230.0   3rd Qu.: 132.00   3rd Qu.:  5.00  
 Max.   :366.0   Max.   : 395.0   Max.   : 264.00   Max.   :315.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.30   1st Qu.: -4.850  
 Median :0   Median :   0.0000   Median :41.57   Median : -1.411  
 Mean   :0   Mean   :   0.2891   Mean   :40.47   Mean   : -2.305  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.38   3rd Qu.:  1.366  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  59.0  
 Median : 370.0  
 Mean   : 548.1  
 3rd Qu.: 790.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 70.0   Min.   :0  
 1st Qu.: 64.0   1st Qu.:  91.0   1st Qu.:  31.00   1st Qu.:188.0   1st Qu.:0  
 Median :126.0   Median : 136.0   Median :  76.00   Median :242.0   Median :0  
 Mean   :157.2   Mean   : 131.1   Mean   :  67.38   Mean   :257.8   Mean   :0  
 3rd Qu.:273.0   3rd Qu.: 178.0   3rd Qu.: 114.00   3rd Qu.:313.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :567.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:   0.000   1st Qu.:40.87   1st Qu.: -4.8458   1st Qu.:  81  
 Median :   0.000   Median :42.08   Median :  0.3056   Median : 370  
 Mean   :   4.288   Mean   :41.28   Mean   : -1.8850   Mean   : 683  
 3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.5242   3rd Qu.: 916  
 Max.   :1199.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   : 21.0   Min.   : 17.0   Min.   :-41.00   Min.   :1528   Min.   :0  
 1st Qu.: 86.0   1st Qu.: 81.5   1st Qu.: 47.00   1st Qu.:1576   1st Qu.:0  
 Median :286.0   Median :126.0   Median : 90.00   Median :1741   Median :0  
 Mean   :219.8   Mean   :136.5   Mean   : 91.35   Mean   :1820   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194.5   3rd Qu.:146.50   3rd Qu.:2036   3rd Qu.:0  
 Max.   :333.0   Max.   :252.0   Max.   :192.00   Max.   :3361   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0    1st Qu.:39.48   1st Qu.:  0.3181   1st Qu.:  69.0  
 Median :0    Median :40.80   Median :  0.4731   Median : 333.0  
 Mean   :0    Mean   :39.48   Mean   : -1.2462   Mean   : 627.3  
 3rd Qu.:0    3rd Qu.:41.72   3rd Qu.:  1.6841   3rd Qu.:1055.0  
 Max.   :0    Max.   :43.36   Max.   :  2.4378   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin             precip         nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   : 437   Min.   :0  
 1st Qu.: 82.0   1st Qu.: 82.0   1st Qu.:  36.50   1st Qu.: 568   1st Qu.:0  
 Median :243.0   Median :134.0   Median :  88.00   Median : 647   Median :0  
 Mean   :198.6   Mean   :131.1   Mean   :  77.81   Mean   : 704   Mean   :0  
 3rd Qu.:305.0   3rd Qu.:179.0   3rd Qu.: 127.00   3rd Qu.: 787   3rd Qu.:0  
 Max.   :366.0   Max.   :344.0   Max.   : 240.00   Max.   :1500   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.82   1st Qu.: -2.0392   1st Qu.:  59.0  
 Median :  0.000   Median :41.83   Median :  0.8856   Median : 287.0  
 Mean   :  3.601   Mean   :41.00   Mean   : -0.8206   Mean   : 700.4  
 3rd Qu.:  0.000   3rd Qu.:42.39   3rd Qu.:  1.9756   3rd Qu.:1055.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin             precip       
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.000  
 1st Qu.: 42.00   1st Qu.: 130.0   1st Qu.:  28.00   1st Qu.:  0.000  
 Median : 84.00   Median : 173.0   Median :  70.00   Median :  0.000  
 Mean   : 86.01   Mean   : 168.7   Mean   :  68.01   Mean   :  8.858  
 3rd Qu.:126.00   3rd Qu.: 215.0   3rd Qu.: 109.00   3rd Qu.:  2.000  
 Max.   :254.00   Max.   : 349.0   Max.   : 239.00   Max.   :172.000  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.48   1st Qu.: -5.346  
 Median :0   Median :   0.0000   Median :41.32   Median : -1.636  
 Mean   :0   Mean   :   0.9457   Mean   :40.11   Mean   : -2.487  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.26   3rd Qu.:  1.272  
 Max.   :0   Max.   :1209.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 333.0  
 Mean   : 516.2  
 3rd Qu.: 775.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin           precip             nevada 
 Min.   : 37.0   Min.   :228.0   Min.   : 47.0   Min.   :  0.0000   Min.   :0  
 1st Qu.:187.0   1st Qu.:285.0   1st Qu.:153.0   1st Qu.:  0.0000   1st Qu.:0  
 Median :215.0   Median :305.0   Median :180.0   Median :  0.0000   Median :0  
 Mean   :214.3   Mean   :309.2   Mean   :178.5   Mean   :  0.9315   Mean   :0  
 3rd Qu.:243.0   3rd Qu.:330.0   3rd Qu.:206.0   3rd Qu.:  0.0000   3rd Qu.:0  
 Max.   :358.0   Max.   :469.0   Max.   :332.0   Max.   :109.0000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :0.00e+00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:0.00e+00   1st Qu.:38.00   1st Qu.: -4.846   1st Qu.:  35.0  
 Median :0.00e+00   Median :40.70   Median : -1.229   Median : 158.0  
 Mean   :1.28e-04   Mean   :39.43   Mean   : -2.391   Mean   : 313.4  
 3rd Qu.:0.00e+00   3rd Qu.:41.63   3rd Qu.:  1.165   3rd Qu.: 582.0  
 Max.   :2.00e+01   Max.   :43.57   Max.   :  4.216   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip      
 Min.   :  4.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.00  
 1st Qu.:273.0   1st Qu.: 134.0   1st Qu.:  40.00   1st Qu.:  0.00  
 Median :307.0   Median : 186.0   Median :  89.00   Median :  0.00  
 Mean   :298.7   Mean   : 177.9   Mean   :  84.64   Mean   : 15.99  
 3rd Qu.:337.0   3rd Qu.: 230.0   3rd Qu.: 132.00   3rd Qu.:  5.00  
 Max.   :366.0   Max.   : 395.0   Max.   : 264.00   Max.   :315.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.30   1st Qu.: -4.850  
 Median :0   Median :   0.0000   Median :41.57   Median : -1.411  
 Mean   :0   Mean   :   0.2891   Mean   :40.47   Mean   : -2.305  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.38   3rd Qu.:  1.366  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  59.0  
 Median : 370.0  
 Mean   : 548.1  
 3rd Qu.: 790.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.00   Min.   : 70.0   Min.   :0  
 1st Qu.: 64.0   1st Qu.:  91.0   1st Qu.:  31.00   1st Qu.:188.0   1st Qu.:0  
 Median :126.0   Median : 136.0   Median :  76.00   Median :242.0   Median :0  
 Mean   :157.2   Mean   : 131.1   Mean   :  67.38   Mean   :257.8   Mean   :0  
 3rd Qu.:273.0   3rd Qu.: 178.0   3rd Qu.: 114.00   3rd Qu.:313.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 372.0   Max.   : 254.00   Max.   :567.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.:   0.000   1st Qu.:40.87   1st Qu.: -4.8458   1st Qu.:  81  
 Median :   0.000   Median :42.08   Median :  0.3056   Median : 370  
 Mean   :   4.288   Mean   :41.28   Mean   : -1.8850   Mean   : 683  
 3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.5242   3rd Qu.: 916  
 Max.   :1199.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   : 21.0   Min.   : 17.0   Min.   :-41.00   Min.   :1528   Min.   :0  
 1st Qu.: 86.0   1st Qu.: 81.5   1st Qu.: 47.00   1st Qu.:1576   1st Qu.:0  
 Median :286.0   Median :126.0   Median : 90.00   Median :1741   Median :0  
 Mean   :219.8   Mean   :136.5   Mean   : 91.35   Mean   :1820   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194.5   3rd Qu.:146.50   3rd Qu.:2036   3rd Qu.:0  
 Max.   :333.0   Max.   :252.0   Max.   :192.00   Max.   :3361   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0    1st Qu.:39.48   1st Qu.:  0.3181   1st Qu.:  69.0  
 Median :0    Median :40.80   Median :  0.4731   Median : 333.0  
 Mean   :0    Mean   :39.48   Mean   : -1.2462   Mean   : 627.3  
 3rd Qu.:0    3rd Qu.:41.72   3rd Qu.:  1.6841   3rd Qu.:1055.0  
 Max.   :0    Max.   :43.36   Max.   :  2.4378   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax             tmin            precip         nevada 
 Min.   : 19.0   Min.   :-28.00   Min.   :-70.00   Min.   :1032   Min.   :0  
 1st Qu.: 81.0   1st Qu.: 87.25   1st Qu.: 47.75   1st Qu.:1090   1st Qu.:0  
 Median :282.5   Median :142.00   Median :103.00   Median :1174   Median :0  
 Mean   :219.4   Mean   :137.82   Mean   : 90.35   Mean   :1200   Mean   :0  
 3rd Qu.:307.0   3rd Qu.:189.25   3rd Qu.:137.25   3rd Qu.:1300   3rd Qu.:0  
 Max.   :357.0   Max.   :282.00   Max.   :213.00   Max.   :1500   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :28.05   Min.   :-17.7550   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.: -0.2387   1st Qu.:  35.0  
 Median :  0.000   Median :41.18   Median :  0.8031   Median : 251.5  
 Mean   :  5.806   Mean   :40.16   Mean   : -0.8885   Mean   : 653.0  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.3642   3rd Qu.:1055.0  
 Max.   :559.000   Max.   :43.57   Max.   :  3.1817   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin             precip      
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.00   1st Qu.:  92.0   1st Qu.:  -7.00   1st Qu.:  0.00  
 Median : 47.00   Median : 126.0   Median :  22.00   Median :  0.00  
 Mean   : 52.71   Mean   : 119.7   Mean   :  20.74   Mean   : 16.41  
 3rd Qu.: 77.00   3rd Qu.: 153.0   3rd Qu.:  51.00   3rd Qu.: 15.00  
 Max.   :222.00   Max.   : 278.0   Max.   : 169.00   Max.   :172.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.70   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.65   Median : -1.293  
 Mean   :0   Mean   :   2.095   Mean   :41.13   Mean   : -1.692  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.366  
 Max.   :0   Max.   :1181.000   Max.   :43.57   Max.   :  4.216  
    altitud    
 Min.   :   1  
 1st Qu.: 143  
 Median : 554  
 Mean   : 672  
 3rd Qu.: 890  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin             precip           nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   : 437.0   Min.   :0  
 1st Qu.: 82.0   1st Qu.: 82.0   1st Qu.:  36.00   1st Qu.: 563.0   1st Qu.:0  
 Median :236.0   Median :133.0   Median :  87.00   Median : 633.0   Median :0  
 Mean   :196.9   Mean   :130.6   Mean   :  76.76   Mean   : 662.5   Mean   :0  
 3rd Qu.:304.0   3rd Qu.:177.5   3rd Qu.: 126.00   3rd Qu.: 745.5   3rd Qu.:0  
 Max.   :366.0   Max.   :344.0   Max.   : 240.00   Max.   :1032.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.95   1st Qu.: -2.3308   1st Qu.:  61.0  
 Median :  0.000   Median :41.84   Median :  0.9844   Median : 287.0  
 Mean   :  3.416   Mean   :41.07   Mean   : -0.8149   Mean   : 704.3  
 3rd Qu.:  0.000   3rd Qu.:42.44   3rd Qu.:  1.9625   3rd Qu.:1055.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin         precip           nevada 
 Min.   :  1.0   Min.   : 37.0   Min.   :-33   Min.   : 0.000   Min.   :0  
 1st Qu.: 81.0   1st Qu.:178.0   1st Qu.: 75   1st Qu.: 0.000   1st Qu.:0  
 Median :116.0   Median :207.0   Median :102   Median : 0.000   Median :0  
 Mean   :112.1   Mean   :207.1   Mean   :105   Mean   : 2.946   Mean   :0  
 3rd Qu.:146.0   3rd Qu.:237.0   3rd Qu.:134   3rd Qu.: 0.000   3rd Qu.:0  
 Max.   :254.0   Max.   :349.0   Max.   :239   Max.   :86.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.96   1st Qu.: -5.698   1st Qu.:  32.0  
 Median :   0.0000   Median :40.96   Median : -1.861   Median : 112.0  
 Mean   :   0.0452   Mean   :39.31   Mean   : -3.110   Mean   : 394.1  
 3rd Qu.:   0.0000   3rd Qu.:42.08   3rd Qu.:  1.168   3rd Qu.: 611.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin           precip             nevada 
 Min.   : 37.0   Min.   :228.0   Min.   : 47.0   Min.   :  0.0000   Min.   :0  
 1st Qu.:187.0   1st Qu.:285.0   1st Qu.:153.0   1st Qu.:  0.0000   1st Qu.:0  
 Median :215.0   Median :305.0   Median :180.0   Median :  0.0000   Median :0  
 Mean   :214.3   Mean   :309.2   Mean   :178.5   Mean   :  0.9315   Mean   :0  
 3rd Qu.:243.0   3rd Qu.:330.0   3rd Qu.:206.0   3rd Qu.:  0.0000   3rd Qu.:0  
 Max.   :358.0   Max.   :469.0   Max.   :332.0   Max.   :109.0000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :0.00e+00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:0.00e+00   1st Qu.:38.00   1st Qu.: -4.846   1st Qu.:  35.0  
 Median :0.00e+00   Median :40.70   Median : -1.229   Median : 158.0  
 Mean   :1.28e-04   Mean   :39.43   Mean   : -2.391   Mean   : 313.4  
 3rd Qu.:0.00e+00   3rd Qu.:41.63   3rd Qu.:  1.165   3rd Qu.: 582.0  
 Max.   :2.00e+01   Max.   :43.57   Max.   :  4.216   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax             tmin             precip       
 Min.   :207.0   Min.   :-158.0   Min.   :-240.00   Min.   :  0.000  
 1st Qu.:321.0   1st Qu.:  80.0   1st Qu.: -13.00   1st Qu.:  0.000  
 Median :338.0   Median : 110.0   Median :  14.00   Median :  0.000  
 Mean   :333.2   Mean   : 105.1   Mean   :   7.81   Mean   :  3.721  
 3rd Qu.:352.0   3rd Qu.: 139.0   3rd Qu.:  36.00   3rd Qu.:  0.000  
 Max.   :366.0   Max.   : 240.0   Max.   :  83.00   Max.   :141.000  
     nevada    prof_nieve           longitud        latitud        
 Min.   :0   Min.   :   0.0000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.84   1st Qu.: -3.7225  
 Median :0   Median :   0.0000   Median :41.70   Median :  0.5933  
 Mean   :0   Mean   :   0.8223   Mean   :41.33   Mean   : -1.0827  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.38   3rd Qu.:  1.5208  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 349.0  
 Median : 687.0  
 Mean   : 877.5  
 3rd Qu.:1056.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin            precip           nevada 
 Min.   :  4.0   Min.   :-104.0   Min.   :-157.0   Min.   :  0.00   Min.   :0  
 1st Qu.:261.0   1st Qu.: 175.0   1st Qu.:  80.0   1st Qu.:  0.00   1st Qu.:0  
 Median :292.0   Median : 211.0   Median : 113.0   Median :  0.00   Median :0  
 Mean   :285.7   Mean   : 205.4   Mean   : 113.6   Mean   : 20.63   Mean   :0  
 3rd Qu.:320.0   3rd Qu.: 240.0   3rd Qu.: 146.0   3rd Qu.: 12.00   3rd Qu.:0  
 Max.   :366.0   Max.   : 395.0   Max.   : 264.0   Max.   :315.00   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:39.48   1st Qu.: -5.649   1st Qu.:  42.0  
 Median :   0.0000   Median :41.39   Median : -1.885   Median : 247.0  
 Mean   :   0.0878   Mean   :40.15   Mean   : -2.767   Mean   : 423.8  
 3rd Qu.:   0.0000   3rd Qu.:42.37   3rd Qu.:  1.272   3rd Qu.: 656.0  
 Max.   :1039.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   :  1.0   Min.   :-60.0   Min.   :-112.0   Min.   :192.0   Min.   :0  
 1st Qu.:213.0   1st Qu.:125.0   1st Qu.:  68.0   1st Qu.:254.0   1st Qu.:0  
 Median :290.0   Median :163.0   Median : 103.0   Median :315.0   Median :0  
 Mean   :256.4   Mean   :167.2   Mean   : 100.8   Mean   :326.8   Mean   :0  
 3rd Qu.:320.0   3rd Qu.:206.0   3rd Qu.: 135.0   3rd Qu.:389.0   3rd Qu.:0  
 Max.   :366.0   Max.   :372.0   Max.   : 254.0   Max.   :567.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.78   1st Qu.: -5.616   1st Qu.:  52.0  
 Median :  0.0000   Median :41.96   Median : -1.117   Median : 252.0  
 Mean   :  0.7224   Mean   :41.14   Mean   : -2.005   Mean   : 485.8  
 3rd Qu.:  0.0000   3rd Qu.:42.53   3rd Qu.:  1.653   3rd Qu.: 667.0  
 Max.   :899.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip         nevada 
 Min.   : 21.0   Min.   : 17.0   Min.   :-41.00   Min.   :1528   Min.   :0  
 1st Qu.: 86.0   1st Qu.: 81.5   1st Qu.: 47.00   1st Qu.:1576   1st Qu.:0  
 Median :286.0   Median :126.0   Median : 90.00   Median :1741   Median :0  
 Mean   :219.8   Mean   :136.5   Mean   : 91.35   Mean   :1820   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194.5   3rd Qu.:146.50   3rd Qu.:2036   3rd Qu.:0  
 Max.   :333.0   Max.   :252.0   Max.   :192.00   Max.   :3361   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0    1st Qu.:39.48   1st Qu.:  0.3181   1st Qu.:  69.0  
 Median :0    Median :40.80   Median :  0.4731   Median : 333.0  
 Mean   :0    Mean   :39.48   Mean   : -1.2462   Mean   : 627.3  
 3rd Qu.:0    3rd Qu.:41.72   3rd Qu.:  1.6841   3rd Qu.:1055.0  
 Max.   :0    Max.   :43.36   Max.   :  2.4378   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax             tmin            precip         nevada 
 Min.   : 19.0   Min.   :-28.00   Min.   :-70.00   Min.   :1032   Min.   :0  
 1st Qu.: 81.0   1st Qu.: 87.25   1st Qu.: 47.75   1st Qu.:1090   1st Qu.:0  
 Median :282.5   Median :142.00   Median :103.00   Median :1174   Median :0  
 Mean   :219.4   Mean   :137.82   Mean   : 90.35   Mean   :1200   Mean   :0  
 3rd Qu.:307.0   3rd Qu.:189.25   3rd Qu.:137.25   3rd Qu.:1300   3rd Qu.:0  
 Max.   :357.0   Max.   :282.00   Max.   :213.00   Max.   :1500   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :28.05   Min.   :-17.7550   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:39.95   1st Qu.: -0.2387   1st Qu.:  35.0  
 Median :  0.000   Median :41.18   Median :  0.8031   Median : 251.5  
 Mean   :  5.806   Mean   :40.16   Mean   : -0.8885   Mean   : 653.0  
 3rd Qu.:  0.000   3rd Qu.:42.24   3rd Qu.:  2.3642   3rd Qu.:1055.0  
 Max.   :559.000   Max.   :43.57   Max.   :  3.1817   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax             tmin             precip     
 Min.   :  1.00   Min.   :-142.0   Min.   :-200.00   Min.   : 70.0  
 1st Qu.: 41.00   1st Qu.:  58.0   1st Qu.:   1.00   1st Qu.:164.0  
 Median : 82.00   Median : 114.0   Median :  53.00   Median :196.0  
 Mean   : 82.56   Mean   : 103.9   Mean   :  42.27   Mean   :205.9  
 3rd Qu.:119.00   3rd Qu.: 155.0   3rd Qu.:  92.00   3rd Qu.:244.0  
 Max.   :361.00   Max.   : 280.0   Max.   : 183.00   Max.   :445.0  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.96   1st Qu.: -4.3075  
 Median :0   Median :   0.000   Median :42.18   Median :  0.3264  
 Mean   :0   Mean   :   6.969   Mean   :41.39   Mean   : -1.7949  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.65   3rd Qu.:  1.4006  
 Max.   :0   Max.   :1199.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 108.0  
 Median : 507.0  
 Mean   : 831.2  
 3rd Qu.:1405.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax             tmin             precip      
 Min.   :  1.00   Min.   :-196.0   Min.   :-252.00   Min.   :  0.00  
 1st Qu.: 23.00   1st Qu.:  92.0   1st Qu.:  -7.00   1st Qu.:  0.00  
 Median : 47.00   Median : 126.0   Median :  22.00   Median :  0.00  
 Mean   : 52.71   Mean   : 119.7   Mean   :  20.74   Mean   : 16.41  
 3rd Qu.: 77.00   3rd Qu.: 153.0   3rd Qu.:  51.00   3rd Qu.: 15.00  
 Max.   :222.00   Max.   : 278.0   Max.   : 169.00   Max.   :172.00  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:40.70   1st Qu.: -4.010  
 Median :0   Median :   0.000   Median :41.65   Median : -1.293  
 Mean   :0   Mean   :   2.095   Mean   :41.13   Mean   : -1.692  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.38   3rd Qu.:  1.366  
 Max.   :0   Max.   :1181.000   Max.   :43.57   Max.   :  4.216  
    altitud    
 Min.   :   1  
 1st Qu.: 143  
 Median : 554  
 Mean   : 672  
 3rd Qu.: 890  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin             precip           nevada 
 Min.   :  1.0   Min.   :-84.0   Min.   :-133.00   Min.   : 437.0   Min.   :0  
 1st Qu.: 82.0   1st Qu.: 82.0   1st Qu.:  36.00   1st Qu.: 563.0   1st Qu.:0  
 Median :236.0   Median :133.0   Median :  87.00   Median : 633.0   Median :0  
 Mean   :196.9   Mean   :130.6   Mean   :  76.76   Mean   : 662.5   Mean   :0  
 3rd Qu.:304.0   3rd Qu.:177.5   3rd Qu.: 126.00   3rd Qu.: 745.5   3rd Qu.:0  
 Max.   :366.0   Max.   :344.0   Max.   : 240.00   Max.   :1032.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.95   1st Qu.: -2.3308   1st Qu.:  61.0  
 Median :  0.000   Median :41.84   Median :  0.9844   Median : 287.0  
 Mean   :  3.416   Mean   :41.07   Mean   : -0.8149   Mean   : 704.3  
 3rd Qu.:  0.000   3rd Qu.:42.44   3rd Qu.:  1.9625   3rd Qu.:1055.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt          tmax            tmin         precip           nevada 
 Min.   :  1.0   Min.   : 37.0   Min.   :-33   Min.   : 0.000   Min.   :0  
 1st Qu.: 81.0   1st Qu.:178.0   1st Qu.: 75   1st Qu.: 0.000   1st Qu.:0  
 Median :116.0   Median :207.0   Median :102   Median : 0.000   Median :0  
 Mean   :112.1   Mean   :207.1   Mean   :105   Mean   : 2.946   Mean   :0  
 3rd Qu.:146.0   3rd Qu.:237.0   3rd Qu.:134   3rd Qu.: 0.000   3rd Qu.:0  
 Max.   :254.0   Max.   :349.0   Max.   :239   Max.   :86.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:37.96   1st Qu.: -5.698   1st Qu.:  32.0  
 Median :   0.0000   Median :40.96   Median : -1.861   Median : 112.0  
 Mean   :   0.0452   Mean   :39.31   Mean   : -3.110   Mean   : 394.1  
 3rd Qu.:   0.0000   3rd Qu.:42.08   3rd Qu.:  1.168   3rd Qu.: 611.0  
 Max.   :1209.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt          tmax            tmin           precip             nevada 
 Min.   : 37.0   Min.   :228.0   Min.   : 47.0   Min.   :  0.0000   Min.   :0  
 1st Qu.:187.0   1st Qu.:285.0   1st Qu.:153.0   1st Qu.:  0.0000   1st Qu.:0  
 Median :215.0   Median :305.0   Median :180.0   Median :  0.0000   Median :0  
 Mean   :214.3   Mean   :309.2   Mean   :178.5   Mean   :  0.9315   Mean   :0  
 3rd Qu.:243.0   3rd Qu.:330.0   3rd Qu.:206.0   3rd Qu.:  0.0000   3rd Qu.:0  
 Max.   :358.0   Max.   :469.0   Max.   :332.0   Max.   :109.0000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :0.00e+00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:0.00e+00   1st Qu.:38.00   1st Qu.: -4.846   1st Qu.:  35.0  
 Median :0.00e+00   Median :40.70   Median : -1.229   Median : 158.0  
 Mean   :1.28e-04   Mean   :39.43   Mean   : -2.391   Mean   : 313.4  
 3rd Qu.:0.00e+00   3rd Qu.:41.63   3rd Qu.:  1.165   3rd Qu.: 582.0  
 Max.   :2.00e+01   Max.   :43.57   Max.   :  4.216   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBkaWEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiA3NgoqIERlc2NyaXBjacOzbjogCiogRnJlY3VlbmNpYTogZGlhCiogVmFyaWFibGVzOiBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcAoqIERpbWVuc2lvbmVzIGRlbCBtYXBhOiAxMCwxMAoqIEl0ZXJhY2lvbmVzOiAxMDAwMAoqIFBhcsOhbWV0cm9zIGFkaWNpb25hbGVzOiAKCmBgYHtyfQpzb3VyY2UoIi4uLy4uL2xpYi9zb20tdXRpbHMuUiIpCnNvdXJjZSgiLi4vLi4vbGliL21hcHMtdXRpbHMuUiIpCmBgYAoKIyBDYXJnYSBkZWwgbW9kZWxvIGRlc2RlIGRpc2NvCgpgYGB7cn0KbXByLnNldF9iYXNlX3BhdGhfYW5hbHlzaXMoKQptb2RlbCA8LSBtcHIubG9hZF9tb2RlbCgic29tLTA3Ni5yZHMueHoiKQpzdW1tYXJ5KG1vZGVsKQpgYGAKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjaGFuZ2VzIikKYGBgCgojIENhcmdhIGRlbCBkYXRhc2V0IGRlIGVudHJhZGEKCmBgYHtyfQpkZiA8LSBtcHIubG9hZF9kYXRhKCJkYXRvc19kaWFfMmsuY3N2Lnh6IikKYGBgCgpgYGB7cn0KZGYKYGBgCgpgYGB7cn0Kc3VtbWFyeShkZikKYGBgCgojIENhcmdhIGRlIGxvcyBtYXBhcwoKYGBge3J9CndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpCnNwYWluIDwtIHN1YnNldCh3b3JsZCwgYWRtaW4gPT0gIlNwYWluIikKYGBgCgojIE1hcGEgZGUgZGVuc2lkYWQKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjb3VudCIsIHNoYXBlID0gInN0cmFpZ2h0IiwgcGFsZXR0ZS5uYW1lID0gbXByLmRlZ3JhZGUuYmxldSkKYGBgCgpOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNlbGRhOgoKYGBge3J9Cm5iIDwtIHRhYmxlKG1vZGVsJHVuaXQuY2xhc3NpZikKcHJpbnQobmIpCmBgYApDb21wcm9iYWNpw7NuIGRlIG5vZG9zIHZhY8Otb3M6CgpgYGB7cn0KZGltX21vZGVsIDwtIDEwKjEwOwpsZW5fbmIgPSBsZW5ndGgobmIpOwplbXB0eV9ub2RlcyA8LSBkaW1fbW9kZWwgIT0gbGVuX25iOwppZiAoZW1wdHlfbm9kZXMpIHsKICBwcmludChwYXN0ZSgiW1dhcm5pbmddIEV4aXN0ZW4gbm9kb3MgdmFjw61vczogIiwgbGVuX25iLCAiLyIsIGRpbV9tb2RlbCkpCn0KYGBgCgojIE1hcGEgZGUgZGlzdGFuY2lhIGVudHJlIHZlY2lub3MKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJkaXN0Lm5laWdoYm91cnMiLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyBJbmZsdWVuY2lhIGRlIGxhcyB2YXJpYWJsZXMKCmBgYHtyfQptb2RlbF9jb2xuYW1lcyA9IGMoImZlY2hhX2NudCIsICJ0bWF4IiwgInRtaW4iLCAicHJlY2lwIikKbW9kZWxfbmNvbCA9IGxlbmd0aChtb2RlbF9jb2xuYW1lcykKYGBgCgojIyBNYXBhIGRlIHZhcmlhYmxlcy4KCmBgYHtyfQpwbG90KG1vZGVsLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyMgTWFwYSBkZSBjYWxvciBwb3IgdmFyaWFibGUKCmBgYHtyfQpwYXIobWZyb3c9YygzLDQpKQpmb3IgKGogaW4gMTptb2RlbF9uY29sKSB7CiAgcGxvdChtb2RlbCwgdHlwZT0icHJvcGVydHkiLCBwcm9wZXJ0eT1nZXRDb2Rlcyhtb2RlbCwxKVssal0sCiAgICBwYWxldHRlLm5hbWU9bXByLmNvb2xCbHVlSG90UmVkLAogICAgbWFpbj1tb2RlbF9jb2xuYW1lc1tqXSwKICAgIGNleD0wLjUsIHNoYXBlID0gInN0cmFpZ2h0IikKfQpgYGAKCiMjIENvcnJlbGFjacOzbiBwYXJhIGNhZGEgY29sdW1uYSBkZWwgdmVjdG9yIGRlIG5vZG9zCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGNvciA8LSBhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwgMiwgbXByLndlaWdodGVkLmNvcnJlbGF0aW9uLCB3PW5iLCBzb209bW9kZWwpCiAgcHJpbnQoY29yKQp9CmBgYAoKUmVwcmVzZW50YWNpw7NuIGRlIGNhZGEgdmFyaWFibGUgZW4gdW4gbWFwYSBkZSBmYWN0b3JlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGFyKG1mcm93PWMoMSwxKSkKICBwbG90KGNvclsxLF0sIGNvclsyLF0sIHhsaW09YygtMSwxKSwgeWxpbT1jKC0xLDEpLCB0eXBlPSJuIikKICBsaW5lcyhjKC0xLDEpLGMoMCwwKSkKICBsaW5lcyhjKDAsMCksYygtMSwxKSkKICB0ZXh0KGNvclsxLF0sIGNvclsyLF0sIGxhYmVscz1tb2RlbF9jb2xuYW1lcywgY2V4PTAuNzUpCiAgc3ltYm9scygwLDAsY2lyY2xlcz0xLGluY2hlcz1GLGFkZD1UKQp9CmBgYAoKSW1wb3J0YW5jaWEgZGUgY2FkYSB2YXJpYWJsZSAtIHZhcmlhbnphIHBvbmRlcmFkYSBwb3IgZWwgdGFtYcOxbyBkZSBsYSBjZWxkYToKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgc2lnbWEyIDwtIHNxcnQoYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksMixmdW5jdGlvbih4LGVmZmVjdGlmKQogICAgIHttPC1zdW0oZWZmZWN0aWYqKHgtd2VpZ2h0ZWQubWVhbih4LGVmZmVjdGlmKSleMikvKHN1bShlZmZlY3RpZiktMSl9LAogICAgIGVmZmVjdGlmPW5iKSkKICBwcmludChzb3J0KHNpZ21hMixkZWNyZWFzaW5nPVQpKQp9CmBgYAoKIyBDbHVzdGVyaW5nCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGhhYyA8LSBtcHIuaGFjKG1vZGVsLCBuYikKfQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDMgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0zKQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9MykKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA0IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTQpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDUgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz01KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NSkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDYgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz02KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NikKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA4IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9OCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTgpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKICBkZi5jbHVzdGVyMDcgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT03KQogIGRmLmNsdXN0ZXIwOCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTgpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0sIGRpbShkZi5jbHVzdGVyMDcpWzFdLCBkaW0oZGYuY2x1c3RlcjA4KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCiAgZGYuY2x1c3RlcjA3Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDcpCiAgZGYuY2x1c3RlcjA4Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDgpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDcuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDguZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAxMCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTEwKQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9MTApCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKICBkZi5jbHVzdGVyMDcgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT03KQogIGRmLmNsdXN0ZXIwOCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTgpCiAgZGYuY2x1c3RlcjA5IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OSkKICBkZi5jbHVzdGVyMTAgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xMCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA5LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMTAgPC0gc2VsZWN0KGRmLmNsdXN0ZXIxMCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMTApCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0sIGRpbShkZi5jbHVzdGVyMDcpWzFdLCBkaW0oZGYuY2x1c3RlcjA4KVsxXSwgZGltKGRmLmNsdXN0ZXIwOSlbMV0sIGRpbShkZi5jbHVzdGVyMTApWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIsICJjbHVzdGVyMDkiLCAiY2x1c3RlcjEwIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIxMCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCiAgZGYuY2x1c3RlcjA3Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDcpCiAgZGYuY2x1c3RlcjA4Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDgpCiAgZGYuY2x1c3RlcjA5Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDkpCiAgZGYuY2x1c3RlcjEwLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMTApCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDcuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDguZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDkuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMTAuZ3JvdXBlZCkKYGBgCg==